#pragma once

#include <string>
#include <memory>
#include <mutex>
#include <mysql_driver.h>
#include <mysql_connection.h>
#include <cppconn/statement.h>
#include <cppconn/resultset.h>
#include <cppconn/prepared_statement.h>
#include <cppconn/exception.h>
#include "DbException.hpp"

namespace http
{
    namespace db
    {
        class DbConnection
        {
        public:
            DbConnection(const std::string &host, const std::string &user, const std::string &password, const std::string &database);
            ~DbConnection();
            DbConnection(const DbConnection &) = delete;
            DbConnection &operator=(const DbConnection &) = delete;

            bool isValid();
            void reconnect();
            void cleanUp();

            template <typename... Args>
            sql::ResultSet *executeQuery(const std::string &sql, Args... args); // 执行查询操作
            template <typename... Args>
            int executeUpdate(const std::string &sql, Args... args); // 执行更新操作

            bool ping(); // 添加检测链接是否有效

        private:
            // preparedStatement 表示 一条已经编译好的 可以多次执行的sql语句
            //  递归模板的终止（递归模板指的是模板递归实例化 不是运行时递归 没有会报错）
            void bindParams(sql::PreparedStatement *stmt, int) {}
            // 辅助函数：绑定参数
            template <typename T, typename... Args>
            void bindParams(sql::PreparedStatement *stmt, int index,
                            T &&value, Args &&...args)
            {
                stmt->setString(index, std::to_string(std::forward<T>(value)));
                bindParams(stmt, index + 1, std::forward<Args>(args)...);
            }

            // // 特化 string 类型的参数绑定
            // template <typename... Args>
            // void bindParams(sql::PreparedStatement *stmt, int index,
            //                 const std::string &value, Args &&...args)
            // {
            //     stmt->setString(index, value);
            //     bindParams(stmt, index + 1, std::forward<Args>(args)...);
            // }

        private:
            std::string _host;                            // 数据库地址
            std::string _user;                            // 数据库用户名
            std::string _password;                        // 数据库密码
            std::string _database;                        // 数据库名
            std::shared_ptr<sql::Connection> _connection; // 数据库连接
            std::mutex _mutex;                            // 互斥锁
        };
    }
}
